package org.springframe.aop;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* @package  org.springframe.aop
* @classname CglibDynamicAopProxy
* @description cglib动态代理
* @version 1.0
* @author luoweiwei
* @date  2021-04-25 13:22:10
*/
public class CglibAopProxy implements AopProxy, MethodInterceptor {

    private Object target;

    private Set<Class> aspectDeclaredClass;

    private Map<Class,Object> aspectMap = new HashMap<>();

    private Enhancer enhancer;

    public CglibAopProxy(Object target, Set<Class> aspectDeclaredClass) {
        this.target = target;
        this.aspectDeclaredClass = aspectDeclaredClass;
        enhancer = new Enhancer();
    }


    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        for (Class declaredClass : aspectDeclaredClass) {
            Object obj;
            if((obj = aspectMap.get(declaredClass))==null){
                obj= declaredClass.getDeclaredConstructor().newInstance();
                aspectMap.put(declaredClass,obj);
            }
            Method[] method1 = declaredClass.getDeclaredMethods();
            for (Method method2 : method1) {
                if(method2.getName().equals("before")){
                    method2.setAccessible(true);
                    method2.invoke(obj,method.getName(),args);
                }
            }

        }
        Object ret = methodProxy.invokeSuper(o,args);
        //调用方法后
        for (Class declaredClass : aspectDeclaredClass) {
            Object obj = aspectMap.get(declaredClass);
            Method[] method1 = declaredClass.getDeclaredMethods();
            for (Method method2 : method1) {
                if(method2.getName().equals("after")){
                    method2.setAccessible(true);
                    method2.invoke(obj,method.getName(),args);
                }
            }
        }
        return ret;
    }

    @Override
    public Object getProxy() {
        return  getProxy(this.getClass().getClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader var1) {
        Class clazz = target.getClass();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
}
